/* 
 * Shuriken is the legal property of its developers. Please refer to the
 * COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace Shuriken.Core.Ranking
{
    /// <summary>
    /// Class for managing a mutable set of integers
    /// </summary>
    /// <remarks>
    /// source: http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Java/Classes/NSMutableIndexSet.html#//apple_ref/java/instm/com.apple.cocoa.foundation.NSMutableIndexSet/addIndexesInRange
    /// 
    /// NSMutableIndexSet manages a mutable collection of unsigned integers. This collection is referred to as an index set and is composed of a series of indexes. A given index can appear only once in an index set. The values in an index set are always sorted, so the order in which values are added is irrelevant.
    /// Internally, indexes are represented in ranges. Thus, an index set includes the integer members of a range or of many ranges. For maximum performance and efficiency, overlapping ranges in an index set are automatically coalesced (ranges merge rather than overlap).
    /// </remarks>
    public class MutableIndexSet : SortedDictionary<int, int>
    {
        public static int NOT_DEFINED = -1; 

        internal void addIndexesInRange(Range matchedRange)
        {
            for (int loop = matchedRange.Location; loop < matchedRange.MaxRange; loop++)
            {
                if (!this.ContainsKey(loop))
                {
                    this.Add(loop, loop);
                }
            }
        }

        public void AddIndex(int number)
        {
            if (!this.ContainsKey(number))
            {
                this.Add(number, number);
            }
        }

        private int[] GetValueArray()
        {
            int[] valArray = new int[this.Values.Count];
            this.Values.CopyTo(valArray, 0);

            return valArray; 
        }

        /// <summary>
        /// Returns the first index. 
        /// </summary>
        public int firstIndex
        {
            get
            {
                int[] vals = GetValueArray(); 

                if (vals.Length > 0)
                {
                    return vals[0];
                }

                return MutableIndexSet.NOT_DEFINED; 
            }
        }

        /// <summary>
        /// Returns last index. 
        /// </summary>
        public int lastIndex
        {
            get
            {
                int[] vals = GetValueArray();

                if (vals.Length > 0)
                {
                    return vals[vals.Length - 1];
                }
                else
                {
                    return MutableIndexSet.NOT_DEFINED; 
                }
            }
        }

        /// <summary>
        /// Returns the Index set ordered into Ranges 
        /// </summary>
        /// <returns>list of ranges</returns>
        public List<Range> GetRanges()
        {
            List<Range> list = new List<Range>();

            int loc = -1;
            int length = 0;
            int prev = -3;
            //bool in_range = false; 

            int[] vals = GetValueArray();

            foreach (int i in vals)
            {
                // check if we have a range 
                if (loc == -1)
                {
                    // make a new range 
                    loc = i;
                    length = 1;
                    //in_range = true; 
                }
                else
                {
                    if (i == prev + 1)
                    {
                        // continues
                        length++;
                    }
                    else
                    {
                        // end of range
                        list.Add(new Range(loc, length));
                        loc = i;
                        length = 1;
                    }
                }

                prev = i; 
            }

            // deal with the last range if needed 
            if (loc > -1 && length > 0)
            {
                list.Add(new Range(loc, length));
            }

            return list; 
        }

        /// <summary>
        /// String representation of the class 
        /// </summary>
        /// <returns>indexes set</returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            int count = this.Count; 

            sb.Append("[");
            for (int loop = 0; loop < this.Count; loop++)
            {
                if (this.ContainsKey(loop))
                {
                    sb.Append(loop);
                    count--;

                    if (count != 0)
                    {
                        sb.Append(",");
                    }
                }
            }
            sb.Append("]");
            return sb.ToString();
        }
    }
}
